﻿
using System;
using System.Collections.Generic;
using System.Linq;

/// MQTT V3.1 协议 做成通用Lambda算子库
namespace LibMQTT.ProtocalIMPL
{
    public static class MqLotLambda
    {
        /// <summary>
        /// MQTT函数 - 128进制编码算法 
        /// 这实际上就是我在<优筑教育>当老师是写过的`任意进制转换算法`</优筑教育>
        /// </summary>
        public static Func<IEnumerable<byte>, byte[]> _GenVLen = (datasource) =>
        {
            long X = datasource.LongCount();
            long encodedByte = 0;
            List<byte> tempResult = new List<byte>();
            do
            {
                // 例如 数字321在UTF8编码+MQTT协议下 被这样拆分 321 = 193+128
                // 编码器会先进行128进制的转换得到2个字节容器长度---> [0xc1].[0x02] 
                encodedByte = X % 128;
                X /= 128;
                if (X > 0)
                    encodedByte |= 128; /* 与|出最高电荷位 */
                tempResult.Add(Convert.ToByte(encodedByte));
            } while (X > 0);

            // 不足4位则补齐4位 变长数据 首部一定为5字节 其余为1字节(只有报文类型+1字节+2字节高低位)
            if (tempResult.Count > 4)
                throw new IndexOutOfRangeException("动态比特流超长~");
            for (int i = 0; i < Math.Abs(5 - tempResult.Count); i++)
                tempResult.Add(0x00);
            return tempResult.ToArray<byte>();
        };

        /// 解码剩余字节值函数 - 128进制解码转换算法
        public static Func<IEnumerable<byte>, int> _DeVLen = (LenSerial) =>
        {
            // 还是不明白IBM公司为什么喜欢使用128进制前端总线的操作系统PowerPC
            if (LenSerial.Count() > 4)
                throw new IndexOutOfRangeException("MQTT可变报文长度不应超4字节");

            int resultVal = 0;
            for (int i = 0, times = 1; i < LenSerial.Count(); i++)
            {
                byte bVal = LenSerial.ElementAt(i);
                resultVal += (bVal & 127) * times;
                times *= 128;
            }
            return resultVal;
        };

        // PUBLISH报文不能将QoS所有的位设置为1。
        // 如果服务端或客户端收到QoS所有位都为1的 
        // PUBLISH报文，它必须关闭网络连接[MQTT - 3.3.1 - 4]
        public static Func<IBMComPacketType, byte> _GenFixH1 = (type) =>
        {
            int MSB = (int)(type) << 4;
            byte resultByte = 0x00;
            if (type == IBMComPacketType.Publish)
            {
                resultByte += 1 << 3; // Dup^1 控制报文的重复分发标识位
                resultByte += 1 << 2; // QoS^2 Publish报文的服务质量等级位
                resultByte += 1 << 1; // QoS^3 Publish报文的服务质量等级位
                resultByte += 0; // RETAIN^3 Pub报文系统保留位
            }
            resultByte += Convert.ToByte(MSB);
            return resultByte;
        };

        /// MQTT内核函数 - <解码BH1数据报文为枚举类型>
        public static Func<byte, IBMComPacketType> _DeFixH1 = (b) =>
        {
            int val = Convert.ToInt32(b);
            int bitVal = val >> 4;
            return (IBMComPacketType)(bitVal);
        };
    }
}
